package com.lytoyo.neihanduanzi.controller;

import com.alibaba.fastjson.JSON;
import com.lytoyo.neihanduanzi.model.user.ChatMsg;
import com.lytoyo.neihanduanzi.model.user.UserInfo;
import com.lytoyo.neihanduanzi.service.ChatMsgService;
import com.lytoyo.neihanduanzi.service.UserService;
import com.lytoyo.neihanduanzi.utils.Constant;
import com.lytoyo.neihanduanzi.utils.WebsocketLocalContainerUtil;

import com.rabbitmq.client.GetResponse;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.core.MessagePropertiesBuilder;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Package:com.lytoyo.neihanduanzi.controller
 *
 * @ClassName:WebSocketController
 * @Create:2025/3/4 10:58
 **/
@Component
@ServerEndpoint(value = "/chat/{userId}")
@Slf4j
public class ChatWebSocketController {

    private static RedisTemplate redisTemplate;

    private static ChatMsgService chatMsgService;

    private static ThreadPoolExecutor threadPoolExecutor;

    private static RabbitTemplate rabbitTemplate;

    private static UserService userService;

    private static Jackson2JsonMessageConverter jsonMessageConverter;

    private static ConnectionFactory connectionFactory;

    @Autowired
    public void setConnectionFactory(ConnectionFactory connectionFactory){
        ChatWebSocketController.connectionFactory = connectionFactory;
    }

    @Autowired
    public void setChatMsgService(ChatMsgService chatMsgService){
        ChatWebSocketController.chatMsgService = chatMsgService;
    }
    @Autowired
    public void setRabbitTemplate(RabbitTemplate rabbitTemplate){
        ChatWebSocketController.rabbitTemplate = rabbitTemplate;
    }

    @Autowired
    public void setJsonMessageConverter(Jackson2JsonMessageConverter jsonMessageConverter){
        ChatWebSocketController.jsonMessageConverter = jsonMessageConverter;
    }

    @Autowired
    public void setUserService(UserService userService){
        ChatWebSocketController.userService = userService;
    }

    @Autowired
    public void setThreadPoolExecutor(ThreadPoolExecutor threadPoolExecutor){
        ChatWebSocketController.threadPoolExecutor = threadPoolExecutor;
    }
    @Autowired
    public void setRedisTemplate(RedisTemplate redisTemplate) {
        ChatWebSocketController.redisTemplate = redisTemplate;
    }


    @OnOpen
    public void onOpen(Session session,@PathParam("userId") Long userId){
        log.info("用户{}建立连接",userId);
        //获取用户基本信息
        UserInfo userInfo = (UserInfo) redisTemplate.opsForValue().get(Constant.USER_LOGIN_KEY+userId);
        if(null == userInfo){
             userInfo = userService.getById(userId);
             if(null != userInfo){
                 redisTemplate.opsForValue().set(Constant.USER_LOGIN_KEY+userId,userInfo,Constant.USER_LOGIN_TTL, TimeUnit.SECONDS);
             }
        }
        //将用户信息关联容器
        WebsocketLocalContainerUtil.addSession(userId,session);
        WebsocketLocalContainerUtil.addUser(userId,userInfo);
        this.pullOfflineMessages(userId);
    }


    @OnMessage
    public void onMessage(String message,Session session){

            ChatMsg chatMsg = JSON.parseObject(message, ChatMsg.class);
            //如果是心跳包则不予理会
            if(chatMsg.getMsgType() == 0) return;
            chatMsgService.save(chatMsg);
            chatMsg = chatMsgService.getById(chatMsg.getId());
            this.sendOrStoreMessage(chatMsg);

    }


    @OnClose
    public void onClose(Session session,@PathParam("userId") Long userId){
        log.info("用户{}断开连接",userId);
        //将用户信息移除容器
        WebsocketLocalContainerUtil.removeSession(userId);
        WebsocketLocalContainerUtil.removeUser(userId);
    }

    //当产生错误时候
    @OnError
    public void onError(Session session,Throwable e){
        log.error("发生错误");
        e.printStackTrace();
    }

    /**
     * 上线后拉取未登录时候的消息
     * @param userId
     */
    private void pullOfflineMessages(Long userId) {
        RabbitTemplate template = new RabbitTemplate(connectionFactory);
        template.setMessageConverter(jsonMessageConverter);
        String queueName = "user."+userId+".queue";
       //逐条获取消息
       while (true){
            ChatMsg chatMsg= (ChatMsg) template.receiveAndConvert(queueName, 3000);
           //消息为空，退出循环
           if(null == chatMsg) break;
           try{
               WebsocketLocalContainerUtil.sendMsg(chatMsg.getOtherUserId(),chatMsg);
               template.execute(channel -> {
                   MessageProperties props = MessagePropertiesBuilder.newInstance().setDeliveryTag(channel.getNextPublishSeqNo()).build();
                   return null;
               });
           }catch (Exception e){
              e.printStackTrace();
           }
       }
    }

    /**
     * 发送消息，当其在线时发送消息，不存在时将信息存储到mq，等下次上线自动拉取
     * @param chatMsg
     */
    private void sendOrStoreMessage(ChatMsg chatMsg) {
        Long receiverId = chatMsg.getOtherUserId();
        //将消息发送给自己

        WebsocketLocalContainerUtil.sendMsg(chatMsg.getUserId(), chatMsg);

        // 检查接收方是否在线
        if (WebsocketLocalContainerUtil.isUserOnline(receiverId)) {
            // 直接发送消息
            WebsocketLocalContainerUtil.sendMsg(chatMsg.getOtherUserId(),chatMsg);
        } else {
            // 存入RabbitMQ（使用用户ID作为路由键）
            rabbitTemplate.convertAndSend(
                    Constant.EXCHANGE_DIRECT_USER_MESSAGE,
                    chatMsg.getOtherUserId().toString(),//路由键=用户ID
                    chatMsg,
                    message -> {
                        // 设置消息持久化
                        message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                        return message;
                    }
            );
        }
    }
}
